package top.zackyoung.thirdlogin.login.impl;

import cn.hutool.http.HttpRequest;
import com.xkcoding.http.support.HttpHeader;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import top.zackyoung.thirdlogin.enums.LoginType;
import top.zackyoung.thirdlogin.login.Login;
import top.zackyoung.thirdlogin.login.OauthService;
import top.zackyoung.thirdlogin.utils.HttpClientUtil;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.HashMap;
import java.util.Map;

/**
 * @author ZackYoung
 * @version 1.0
 * @description
 * @date 2021/6/5 14:31
 */
@Service("github")
public class LoginGithub implements Login {
    @Resource
    OauthService oauthService;
    @Value("${github.client.id}")
    private String GITHUB_CLIENT_ID;
    @Value("${github.client.secret}")
    private String GITHUB_CLIENT_SECRET;
    @Value("${github.redirect.url}")
    private String GITHUB_REDIRECT_URL;
@Resource
    HttpSession session;
    @Override
    public String login() {
        // Github认证服务器地址
        String url = "https://github.com/login/oauth/authorize";
        // 生成并保存state，忽略该参数有可能导致CSRF攻击
        String state = oauthService.genState(LoginType.GITHUB);
        // 传递参数response_type、client_id、state、redirect_uri
        String param = "response_type=code&" + "client_id=" + GITHUB_CLIENT_ID + "&state=" + state
                + "&redirect_uri=" + GITHUB_REDIRECT_URL;
        // 1、请求Github认证服务器
        return url + "?" + param;
    }

    @SneakyThrows
    @Override
    public String callback(String state, String code) {
        // 验证state，如果不一致，可能被CSRF攻击
        if (!oauthService.checkState(LoginType.GITHUB, state)) {
            throw new Exception("State验证失败");
        }

        // 2、向GitHub认证服务器申请令牌
        String url = "https://github.com/login/oauth/access_token";
        // 传递参数grant_type、code、redirect_uri、client_id
        String param = "grant_type=authorization_code&code=" + code + "&redirect_uri=" +
                GITHUB_REDIRECT_URL + "&client_id=" + GITHUB_CLIENT_ID + "&client_secret=" + GITHUB_CLIENT_SECRET;

        // 申请令牌，注意此处为post请求
        String result = HttpClientUtil.post(url, param, true);
        /*
         * result示例：
         * 失败：error=incorrect_client_credentials&error_description=The+client_id+and%2For+client_secret+passed+are+incorrect.&
         * error_uri=https%3A%2F%2Fdeveloper.github.com%2Fapps%2Fmanaging-oauth-apps%2Ftroubleshooting-oauth-app-access-token-request-errors%2F%23incorrect-client-credentials
         * 成功：access_token=7c76186067e20d6309654c2bcc1545e41bac9c61&scope=&token_type=bearer
         */
        Map<String, String> resultMap = HttpClientUtil.params2Map(result);
        // 如果返回的map中包含error，表示失败，错误原因存储在error_description
        if (resultMap.containsKey("error")) {
            throw new Exception(resultMap.get("error_description"));
        }

        // 如果返回结果中包含access_token，表示成功
        if (!resultMap.containsKey("access_token")) {
            throw new Exception("获取token失败");
        }

        // 得到token和token_type
        String accessToken = resultMap.get("access_token");
        String tokenType = resultMap.get("token_type");

        // 3、向资源服务器请求用户信息，携带access_token和tokenType
        String userUrl = "https://api.github.com/user";
        String userParam = "access_token=" + accessToken + "&token_type=" + tokenType;
        Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", 10808));
        Map<String, String> header=new HashMap<>();
        header.put("Authorization", "token " + accessToken);
        // 申请资源
        return HttpRequest.get(userUrl+"?"+userParam).setProxy(proxy).addHeaders(header).execute().body();
    }
}
